package it.unibo.refolding.pico;

import java.util.Arrays;

import com.google.common.base.Preconditions;

// TODO: move to stripchart package
public class StripChartPicoData extends PicoData {

	private final StripChartDirectionData approach;

	public final int stripChartRateHz;

	public StripChartPicoData(
			double xOffsetM, double springConstantNPerM, double sensZSensMPerV,
			double zScanStartHardValueV, double zLsbToMetresFactor,
			double deflectionLimitV, double deflectionSensitivityMPerV, StripChartDirectionData approach,
			int stripChartRateHz) {
		super(xOffsetM, springConstantNPerM, sensZSensMPerV, zScanStartHardValueV, zLsbToMetresFactor,
		  deflectionLimitV, deflectionSensitivityMPerV);
		Preconditions.checkArgument(stripChartRateHz > 0);
		this.approach = Preconditions.checkNotNull(approach,
				"Both plain force curves and strip charts must have the approach array filled in.");
		this.stripChartRateHz = stripChartRateHz;
	}

	@Override
	public boolean equals(Object other) {
		if (!super.equals(other)) {
			return false;
		}
		StripChartPicoData o = (StripChartPicoData) other;
		return approach.equals(o.approach) & stripChartRateHz == o.stripChartRateHz;
	}

	@Override
	public StripChartPicoData withSpringConstant(double fixedSpringConstantNPerM) {
		return new StripChartPicoData(xOffsetM, fixedSpringConstantNPerM, sensZSensMPerV,
			zScanStartHardValueV, zLsbToMetresFactor, deflectionLimitV, deflectionSensitivityMPerV,
			approach, stripChartRateHz);
	}

	public double totalTimeSeconds() {
		// Not sure if I should really subtract one here.
		return stripChartRateHz * (approach.timeInstantCount() - 1);
	}

	@Override
	public AbstractDirectionData sharedApproach() {
		return approach;
	}

	@Override
	public StripChartPicoData withZScanStartM(double zScanStartM) {
		double newZScanStartHardValueV = zScanStartM / sensZSensMPerV;
		return withZScanStartHardValueV(newZScanStartHardValueV);
	}
	
	private StripChartPicoData withZScanStartHardValueV(
		double zScanStartHardValueV) {
		return new StripChartPicoData(
				xOffsetM, springConstantNPerM, sensZSensMPerV, zScanStartHardValueV,
				zLsbToMetresFactor, deflectionLimitV, deflectionSensitivityMPerV, approach, stripChartRateHz);
	}

	@Override
	public short[] minMaxDeflection() {
		return approach.minMaxDeflection();
	}

	@Override
	public short[] copyOfFullDeflectionArray() {
		return Arrays.copyOf(sharedApproach().deflection, sharedApproach().deflection.length);
	}

	@Override
	public short[] copyOfFullZArray() {
		return Arrays.copyOf(sharedApproach().z, sharedApproach().z.length);
	}

	/**
	 * Potentially shared.
	 */
	public StripChartPicoData subRange(int from, int to) {
	  if (from == 0 & to == timeInstantCount()) {
	    return this;
	  }
		return new StripChartPicoData(
			xOffsetM, springConstantNPerM, sensZSensMPerV,
			zScanStartHardValueV, zLsbToMetresFactor,
			deflectionLimitV, deflectionSensitivityMPerV, approach.subRange(from, to),
			stripChartRateHz);
	}

	public int timeInstantCount() {
		return approach.timeInstantCount();
	}

	public boolean equalsIgnoringZScanStart(StripChartPicoData o) {
		return this.withZScanStartHardValueV(o.zScanStartHardValueV).equals(o);
	}

    @Override
    public PicoData withDeflectionSensitivity(double fixedDeflectionSensitivityMPerV) {
        return new StripChartPicoData(
            xOffsetM, springConstantNPerM, sensZSensMPerV, zScanStartHardValueV,
            zLsbToMetresFactor, deflectionLimitV, fixedDeflectionSensitivityMPerV, approach, stripChartRateHz);
    }
}
